#include "DirectoryTree.h"
#include "FileOperations.h"
#include <stack>
using namespace std;
DirectoryTree::DirectoryTree()
{
	Parent = NULL;
	Speed = 100;
}
DirectoryTree::~DirectoryTree()
{
	Clear();
}
void DirectoryTree::Clear()
{
	DirectoryEntry* file;
	DirectoryTree* folder;
	Folder.clear();
	while (!Files.empty())
	{
		file = Files.front();
		Files.pop_front();
		delete file;
	}
	while (!Folders.empty())
	{
		folder = Folders.front();
		Folders.pop_front();
		delete folder;
	}
}
DirectoryTree *DirectoryTree::GrandParent()
{
	DirectoryTree* loop = this;
	DirectoryTree* parent;
	while((parent = loop->Parent)!=NULL)
	{
		loop = parent;
	}
	return loop;
}
void DirectoryTree::GetFullPath(const gstring *fileName, gstring &output)
{
	size_t length;
	DirectoryTree* loop;
	stack<gstring*> folders; // I use a stack to reverse the order of the folders.
	gstring* folder;
	size_t fileNameLength = (fileName == NULL ? 0 : fileName->size());
	length = fileNameLength;
	for (loop = this; loop != NULL; loop = loop->Parent)
	{
		length += (loop->Folder.size() + 1);
		folders.push(&loop->Folder);
	}
	output.clear();
	output.reserve(length + 1);
	while (!folders.empty())
	{
		folder = folders.top();
		folders.pop();
		if (output.size() > 0)
		{
			output += FileOperations::DirectorySeparator();
		}
		output += *folder;
	}
	if ((output.size() > 0) && (fileNameLength > 0))
	{
		output += FileOperations::DirectorySeparator();
	}
	if (fileNameLength > 0)
	{
		output += *fileName;
	}
}
void DirectoryTree::ReadDirectory(bool recursive)
{
	DirectoryListing* listing;
	DirectoryTree* newTree;
	DirectoryEntry* newEntry;
	gstring folder;	
		
	GetFullPath(NULL, folder);
	listing = new DirectoryListing();
	listing->ReadDirectory(folder);
	while ((newEntry = listing->Pop()) != NULL)
	{
		if (newEntry->IsDirectory())
		{
			// Directory
			newTree = new DirectoryTree();
			newTree->Folder.swap(newEntry->FileName); // newTree->Folder = newEntry->FileName.
			newTree->Parent = this;
			Folders.push_back(newTree);
			newTree = NULL;
			delete newEntry;
		}
		else {
			// File
			Files.push_back(newEntry);
		}
	}
	delete listing;
	listing = NULL;
	folder.clear();
	if (recursive)
	{
		for (auto& folder : Folders)
		{
			if (Speed < 100)
			{
				FileOperations::SleepMilliseconds(99 - Speed);
			}
			folder->ReadDirectory(recursive);
		}
	}
}

int DirectoryTree::FileCount(bool recurseFolders)
{
	int count = 0;
	count = (int)Files.size();
	if (recurseFolders)
	{
		for (auto& folder : Folders)
		{
			count += folder->FileCount(recurseFolders);
		}
	}
	return count;
}